home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / SAT 2.4.0 / SAT / Demo ƒ / HeartQuest demo ƒ / main.p < prev    next >
Encoding:
Text File  |  1997-02-16  |  13.7 KB  |  421 lines  |  [TEXT/PJMM]

  1. {================================================}
  2. {=============== HeartQuest main unit ================}
  3. {================================================}
  4.  
  5. { Example file for Ingemars Sprite Animation Toolkit. }
  6. { © Ingemar Ragnemalm 1992 }
  7. { See doc files for legal terms for using this code. }
  8.  
  9. { HeartQuest is a very simple game demonstrating how to use the Sprite Animation}
  10. { Toolkit. I originally wrote the game as my present to my wife Eva for Valentine's}
  11. { day 1992. You can still tell that this file once started as the Skel example in the}
  12. { TransSkel package by Paul DuBois and Owen Hartnett. }
  13.  
  14. { This "main" file is rather small, and holds very little game specific code.}
  15. { Its main concern is to initialize the various parts of the game, and to hold the}
  16. { file and edit menu handlers. }
  17.  
  18. program HeartQuest;
  19.  
  20.     uses
  21. {$IFC UNDEFINED THINK_PASCAL}
  22.         Types, Quickdraw, Events, Windows, Resources, Fonts, {}
  23.         Menus, Memory, QuickDrawText, Errors, OSUtils, EPPC, 
  24. {$ENDC}
  25.         TransSkel, SAT, GameGlobals, GameWindow, {sound,}
  26.         SoundConst, scores, CenterStuff, Preferences, AppleEvents, ClutFade, SATSetDepth, sBonus;
  27.  
  28. {Variables for the main program}
  29.     var
  30.         keys: KeyMap;
  31.         zoomFlag: Boolean;
  32.         ignore: longint;                        {For UnloadScrap error}
  33.         gAppleEventsInitialized: Boolean;    {For initializing Apple Events when necessary}
  34.  
  35. { -------------------------------------------------------------------- }
  36. {                        Menu handling procedures                        }
  37. { -------------------------------------------------------------------- }
  38.  
  39. {    Handle selection of "About…" item from Apple menu}
  40.  
  41.     procedure DoAbout;
  42.         var
  43.             selection: integer;
  44.     begin
  45.         selection := DoAlert(43, aboutAlrt, nil);
  46.         if selection = 2 then
  47.             selection := DoAlert(43, evaAlrt, nil);
  48.     end;
  49.  
  50. {    Process selection from File menu.}
  51.  
  52. {    HelpEnemies    Shows a help box. }
  53. {    Quit    Request a halt by calling SkelHalt().  This makes SkelMain}
  54. {            return.}
  55.  
  56.     procedure DoFileMenu (item: integer);
  57.         var
  58.             ignore: integer;
  59.     begin
  60.         case item of
  61.             fm_helpenemies: 
  62.                 ignore := DoAlert(43, helpenemiesAlrt, nil);
  63.             fm_setStrings: 
  64.                 SetStrings;
  65.             otherwise
  66.                 begin
  67.                     if pauseFlag then
  68.                         DoGameOver;
  69.                     SkelWhoa;
  70.                 end;
  71.         end;
  72.     end; {DoFileMenu}
  73.  
  74.     procedure DoEditMenu;
  75.     begin
  76.     end;
  77.  
  78. {    Initialize menus.  Tell TransSkel to process the Apple menu}
  79. {    automatically, and associate the proper procedures with the}
  80. {    File and Edit menus.}
  81.  
  82.     procedure SetUpMenus;
  83.     begin
  84.         SkelApple(MyGetIndString(aboutStrID), @DoAbout); {string 1: About HeartQuest…}
  85.         fileMenu := GetMenu(fileMenuRes);
  86.         editMenu := GetMenu(editMenuRes);
  87.         GameMenu := GetMenu(GameMenuRes);
  88.         highMenu := GetMenu(highMenuRes);
  89.         dummy := SkelMenu(fileMenu, @DoFileMenu, nil, false);
  90.         dummy := SkelMenu(editMenu, @DoEditMenu, nil, false);
  91.         dummy := SkelMenu(GameMenu, @DoGameMenu, nil, false);
  92.         dummy := SkelMenu(highMenu, @DoHighMenu, nil, true);
  93.     end;
  94.  
  95. { Initialize settings resources. These are saved in the game file itself. This is elegant,}
  96. { but a bit "server-hostile". An alternative is to create a preference file in the system}
  97. { folder. The routine determining where preferences should be saved, in Preferences.p,}
  98. { has a parameter that can be set to always save in a preference file, if you prefer that.}
  99.  
  100.     procedure InitSettings;
  101.     begin
  102.         UseResFile(gPrefFile); {set the resfile to the pref file, if any. If none, gPrefFile will be the app itself!}
  103.         features := featHnd(GetResource('Feat', 0));        { Load the settings }
  104.         if features = nil then                                { Settings doesn't exist; create new }
  105.             begin
  106.                 features := featHnd(NewHandle(Sizeof(featRec)));
  107.                 CheckNoMem(Ptr(features));
  108.                 features^^.sound := true;
  109.                 features^^.allowBG := false;
  110.                 features^^.player := MyGetIndString(anonymousStrID); {str 2: Anonymous}
  111.                 features^^.macho := false;
  112.                 features^^.sweetString1 := 'Eva';
  113.                 features^^.sweetString2 := 'är söt';
  114.                 AddResource(handle(features), 'Feat', 0, 'Settings');
  115.             end
  116.         else                                                    {Did exist - check the size!}
  117.             if GetHandleSize(Handle(features)) < SizeOf(FeatRec) then
  118.                 begin
  119.                     SetHandleSize(Handle(features), SizeOf(FeatRec));
  120. {These are likely not to be in too small feature records:}
  121.                     features^^.sweetString1 := 'Eva';
  122.                     features^^.sweetString2 := 'är söt';
  123.                 end;
  124.         UseResFile(gAppFile);
  125.  
  126. { Fix all checkmarks in the menus }
  127.         if features^^.sound then
  128.             begin
  129.                 features^^.sound := false;
  130.                 DoGameMenu(sound);
  131.             end
  132.         else
  133.             begin
  134.                 features^^.sound := true;
  135.                 DoGameMenu(sound);
  136.             end;
  137.         if features^^.macho then
  138.             begin
  139.                 features^^.macho := false;
  140.                 DoGameMenu(macho);
  141.             end
  142.         else
  143.             begin
  144.                 features^^.macho := true;
  145.                 DoGameMenu(macho);
  146.             end;
  147.         if features^^.PlotFast then
  148.             begin
  149.                 features^^.PlotFast := false;
  150.                 DoGameMenu(FastAnimation);
  151.             end
  152.         else
  153.             begin
  154.                 features^^.PlotFast := true;
  155.                 DoGameMenu(FastAnimation);
  156.             end;
  157.         if features^^.allowBG then
  158.             begin
  159.                 features^^.allowBG := false;
  160.                 DoGameMenu(allowBG);
  161.             end
  162.         else
  163.             begin
  164.                 features^^.allowBG := true;
  165.                 DoGameMenu(allowBG);
  166.             end;
  167.     end;
  168.  
  169.  
  170. { ******* MultiFinder and Apple events: ******* }
  171.  
  172. {MultiFinder events - suspend and reume - have been handled by HeartQuest since very early versions,}
  173. {since I want it to hide its window when switched out.}
  174. {AppleEvents are added, mostly because I wanted to learn about it. I learned one thing: Apple Events are}
  175. {tedious. I tried simplifying AppleEvent support by installing my handlers first after getting an Apple}
  176. {Event (getting rid of all checking for its existence - if it sends events to me, it exists) - but the interface}
  177. {files needed are horrible. To speed up compilation, I made a stripped down interface file, HQAE.p.}
  178. {All I really got by supporting Apple Events is that I can quit after getting the 'quit' Apple event.}
  179.  
  180. {Handle the required Apple events:}
  181. {DoOpenApp,DoOpenDoc,DoPrintDoc,DoQuitApp}
  182. {MyGotRequiredParams: From MSG demo my Mark Pilgrim, tells whether we have handled all we have to or not.}
  183.     function MyGotRequiredParams (theAppleEvent: AppleEvent): OSErr;
  184.         var
  185.             returnedType: DescType;
  186.             actualSize: Size;
  187.     begin
  188.         if AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard, returnedType, nil, 0, actualSize) = errAEDescNotFound then
  189.             MyGotRequiredParams := noErr
  190.         else
  191.             MyGotRequiredParams := errAEParamMissed;
  192.     end;
  193.     function DoOpenApp (theAppleEvent, reply: AppleEvent; refCon: Longint): OSErr;
  194.     begin
  195. {What am I supposed to do here?}
  196.         DoOpenApp := MyGotRequiredParams(theAppleEvent);
  197.     end;
  198.     function DoOpenDoc (theAppleEvent, reply: AppleEvent; refCon: Longint): OSErr;
  199.     begin
  200.         DoOpenDoc := errAEEventNotHandled; {We don't open any documents!}
  201.     end;
  202.     function DoPrintDoc (theAppleEvent, reply: AppleEvent; refCon: Longint): OSErr;
  203.     begin
  204.         DoPrintDoc := errAEEventNotHandled; {We don't print any documents!}
  205.     end;
  206.     function DoQuitApp (theAppleEvent, reply: AppleEvent; refCon: Longint): OSErr;
  207.     begin
  208.         SkelWhoa;            {If I'm told to quit, I'll quit.}
  209.         DoQuitApp := MyGotRequiredParams(theAppleEvent);
  210.     end;
  211.  
  212. {Init Apple events}
  213. {Perhaps I'm cheating, but I don't call this until I get the first Apple event.}
  214. {IMHO, that's the simplest way to support them without a lot of boring Gestalt checks.}
  215.     procedure AppleEventInit;
  216.         var
  217.             error: OSerr;
  218.     begin
  219.         if gAppleEventsInitialized then
  220.             exit(AppleEventInit);
  221.         gAppleEventsInitialized := true;
  222.         error := AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, @DoOpenApp, 0, false);
  223.         error := AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, @DoOpenDoc, 0, false);
  224.         error := AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, @DoPrintDoc, 0, false);
  225.         error := AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, @DoQuitApp, 0, false);
  226. {I ignore errors.}
  227.     end;
  228.  
  229.  
  230. {Event processing that TransSkel nowadays HAS support for:}
  231. {MultiFinder events: Hide gameWindow on suspend, so the user can get access to disk icons etc.}
  232. {Apple Events: Handle the required Apple events.}
  233.  
  234.     procedure DoSuspendResume (b: Boolean);
  235.     begin
  236.         if b then
  237. {Resume event: show game window and set the sleep time to something fairly low}
  238.             begin
  239.                 ShowWindow(gSAT.wind.port);
  240.                 SelectWindow(gSAT.wind.port);
  241.                 SkelSetSleep(5);
  242.             end
  243.         else
  244. {Suspend event: Hide the game window and set the sleep time to something high}
  245. {(Not that the sleep time matters when "can background" is false, but I put it in for demonstrating it.)}
  246.             begin
  247.                 HideWindow(gSAT.wind.port);
  248.                 SkelSetSleep(60);
  249.             end;
  250.     end;
  251.  
  252.     function DoEvt (e: eventRecord): boolean;
  253.     begin
  254. {In older versions, we handled Apple events and suspend/resume events here. Since then,}
  255. {I have added support for them in TransSkel.p, so now this is only used for installing our}
  256. {Apple Event handlers upon acceptance of the first Apple Event.}
  257.  
  258. {Old obsolete code: Handle suspend/resume events}
  259. {if e.what = OSevt then}
  260. {begin}
  261. {if BAND(BROTL(e.message, 8), $FF) = SuspendResumeMessage then}
  262. {DoSuspendResume(BAnd(e.message, 1) <> 0);}
  263. {DoEvt := true;}
  264. {end}
  265. {else}
  266.  
  267.         DoEvt := false; {We never actually PROCESS any event here!}
  268.         if e.what = kHighLevelEvent then
  269.             if not gAppleEventsInitialized then {My little "cheat" into compatibility}
  270.                 AppleEventInit;
  271. {if AEProcessAppleEvent(e) <> noErr then}
  272.     end; { DoEvt }
  273.  
  274.  
  275.     procedure EmergencyExit;
  276.     begin
  277. {Fade back in on emergency exits, so we don't leave the screen faded!}
  278.         FadeScreen(1, false, fadeTo);
  279.     end; {EmergencyExit}
  280.  
  281.     var
  282.         loadWind: WindowPtr;
  283.  
  284.     procedure ShowLoadWind;
  285.         var
  286.             s: Str255;
  287.             fontNum: Integer;
  288.             world: SysEnvRec;
  289.             tempColorFlag: Boolean;
  290.             height, width: Integer;
  291.     begin
  292.         tempColorFlag := false;
  293.         if noErr = SysEnvirons(1, world) then
  294.             if world.hasColorQd then
  295.                 tempColorFlag := true;
  296. {$IFC UNDEFINED THINK_PASCAL}
  297.         if tempColorFlag then
  298.             loadWind := NewCWindow(nil, qd.screenBits.bounds, '', true, plainDBox, WindowPtr(-1), false, 0)
  299.         else
  300.             loadWind := NewWindow(nil, qd.screenBits.bounds, '', true, plainDBox, WindowPtr(-1), false, 0);
  301. {$ELSEC}
  302.         if tempColorFlag then
  303.             loadWind := NewCWindow(nil, screenBits.bounds, '', true, plainDBox, WindowPtr(-1), false, 0)
  304.         else
  305.             loadWind := NewWindow(nil, screenBits.bounds, '', true, plainDBox, WindowPtr(-1), false, 0);
  306. {$ENDC}
  307.  
  308. {Up with the loading window and draw SOMETHING}
  309.         SetPort(loadWind);
  310. {Paint the window pink}
  311.         if tempColorFlag then
  312.             RGBForeColor(fadeTo);
  313.         PaintRect(loadWind^.portRect);
  314. {Select 24-point Geneva}
  315.         TextSize(24);
  316.         TextFace([bold]);
  317.         GetFNum('Geneva', fontNum);
  318.         TextFont(fontNum);
  319. {Get the loading string and draw it}
  320.         s := MyGetIndString(loadingStrID);
  321.         height := loadWind^.portRect.bottom - loadWind^.portRect.top;
  322.         width := loadWind^.portRect.right - loadWind^.portRect.left;
  323.         MoveTo(width div 2 - StringWidth(s) div 2, height div 2);
  324.         ForeColor(redColor);
  325.         DrawString(s);
  326.         ForeColor(blackColor);
  327.     end; {ShowLoadWind}
  328.  
  329. { -------------------------------------------------------------------- }
  330. {                                    Main                                }
  331. { -------------------------------------------------------------------- }
  332.  
  333.     var
  334.         r: Rect;
  335.  
  336. begin
  337.     SkelInit(6, nil);                { initialize }
  338.     SetUpMenus;                { install menu handlers }
  339.  
  340.     SetCursor(GetCursor(watchCursor)^^);
  341.  
  342. {Using the SATSetDepth unit, I switch to 256 colors if available. If not, just leave it.}
  343.     if SATHasDepth(nil, 8) then
  344.         if noErr = SATSetDepth(nil, 8) then
  345.             ;
  346.  
  347. {Is the user holding down a modifier key? If so, we should use the whole screen.}
  348.     GetKeys(keys);
  349.     zoomFlag := keys[55] or keys[56] or keys[58] or keys[59]; {cmd, shift, alt, ctrl}
  350.  
  351. {Tell SAT that we want it to rescale the PICTs}
  352.     SATConfigure(true, kVPositionSort, kKindCollision, 32);
  353.  
  354. {Send strings from resources to SAT, so the program can be localized.}
  355.     SATSetStrings(MyGetIndString(okStrID), MyGetIndString(yesStrID), MyGetIndString(noStrID), MyGetIndString(quitStrID), MyGetIndString(memerrStrID), MyGetIndString(noscreenStrID), MyGetIndString(satnopictStrID), MyGetIndString(nowindStrID));
  356.  
  357. {Before fading, set the emergency exit routine to one where we restore the screen!}
  358.     SATInstallEmergency(@EmergencyExit);
  359.  
  360.     fadeTo.red := -1;
  361.     fadeTo.green := 26214; {Was $a000}
  362.     fadeTo.blue := -1; {was $a000}
  363.     FadeScreen(30, true, fadeTo);
  364.     ShowLoadWind;
  365.     FadeScreen(30, false, fadeTo);
  366.  
  367. { Set the randseed to something that is random enough. }
  368. {$IFC UNDEFINED THINK_PASCAL}
  369.     qd.randSeed := TickCount;
  370. {$ELSEC}
  371.     randSeed := TickCount;
  372. {$ENDC}
  373.  
  374. { Initialize the Sprite Animation Toolkit, set up offscreen buffers and make the window. }
  375.  
  376.     if zoomFlag then {if cmd, shift, alt, ctrl}
  377.         SetRect(r, 0, 0, 32000, 32000) {Very big - makes SAT cut it down to the main screen.}
  378.     else
  379.         SetRect(r, 0, 0, 640, 480); {Standard size}
  380. {We now prefer 640x480. Older versions used 512x342, but that is a bit too small to use as}
  381. {preferred size these days.}
  382.  
  383. {No pictures here. We load them in DrawBackground. You can do the same and use patterns or}
  384. {whatever you like, or do it the easy way and have it done with SATInit.}
  385.     SATCustomInit(0, 0, r, nil, nil, true, true, true, true, true);
  386.  
  387. {Here we can call SATSoundInitChannels if we want more than one channel.}
  388.     if SATSoundInitChannels(2) < 2 then
  389.         ;
  390.     SATPreloadChannels;
  391.  
  392.     Loadsounds;        { preload all sound resources }
  393.     InitScores;        { Init the score module, check if a pref file should be created }
  394.     InitSettings;    { Load the settings }
  395.  
  396. { Init all the different parts of the game. }
  397.     GameWindInit;    { Init the game window }
  398.  
  399. { Initialize the sprites }
  400.     InitSprites;
  401. {We draw some of the background -the trees - ourselves in this game.}
  402.     DrawBackground;
  403.  
  404.     FadeScreen(30, true, fadeTo);
  405. { Draw the contents of the window (to give the user something to look at during the rest of startup). }
  406.     DisposeWindow(loadWind);
  407.     ShowWindow(gSAT.wind.port);
  408.     SelectWindow(gSAT.wind.port);
  409.     HQRedraw;
  410.     FadeScreen(30, false, fadeTo);
  411.  
  412.     SkelEventHook(@DoEvt); { handle MultiFinder-events }
  413.     SkelSetSuspendResume(@DoSuspendResume); {NEW call in my version of TransSkel 2.0}
  414.     InitCursor;
  415.  
  416.     SkelMain;                { loop 'til Quit selected }
  417.     SkelClobber;                { clean up }
  418.     SATSoundShutUp;            { Terminate sounds }
  419.  
  420.     SATRestoreDepth;
  421. end.